package com.renren.yx.base.dao;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;

import javax.sql.DataSource;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

@SuppressWarnings({ "unchecked", "deprecation", "rawtypes", "hiding" })
public class GenericDao<T extends Serializable, PK extends Serializable>
		extends HibernateDaoSupport {

	private SimpleJdbcTemplate jdbcTemplate;

	/**
	 * 
	 * @param entity
	 * @return
	 */
	public T addEntity(T entity) {
		this.getHibernateTemplate().save(entity);
		return entity;
	}

	/**
	 * 
	 * @param entity
	 */
	public void delEntity(T entity) {
		this.getHibernateTemplate().delete(entity);
	}

	/**
	 * 
	 * @param entity
	 */
	public void updateEntity(T entity) {
		this.getHibernateTemplate().update(entity);
	}

	/**
	 * 
	 * @param type
	 * @param id
	 * @return
	 */
	public T getEntity(Class<T> type, PK id) {
		return (T) this.getHibernateTemplate().get(type, id);
	}

	/**
	 * 
	 * @param hql
	 * @param values
	 * @return
	 */
	public Object findEntity(final String hql, final Object... values) {
		List<T> list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(hql);
						int i = 0;
						for (Object object : values) {
							query.setParameter(i, object);
							i++;
						}
						query.setFirstResult(0);
						query.setMaxResults(1);
						List list = query.list();
						return list;
					}
				});
		if (list != null && list.size() > 0)
			return list.get(0);
		return null;

	}

	/**
	 * 
	 * @param hql
	 * @param values
	 * @return
	 */
	public List<T> findEntities(final String hql, final Object... values) {
		List<T> list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(hql);
						int i = 0;
						for (Object object : values) {
							query.setParameter(i, object);
							i++;
						}
						List list = query.list();
						return list;
					}
				});
		return list;

	}

	/**
	 * 
	 * @param hql
	 * @param curpage
	 * @param pagesize
	 * @param values
	 * @return
	 */
	public List<T> findEntitiesForPage(final String hql, final int curpage,
			final int pagesize, final Object... values) {
		List<T> list = this.getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(hql);
						int i = 0;
						for (Object object : values) {
							query.setParameter(i, object);
							i++;
						}
						query.setFirstResult((curpage - 1) * pagesize);
						query.setMaxResults(pagesize);
						List list = query.list();
						return list;
					}
				});
		return list;
	}

	/**
	 * 
	 * @param hql
	 * @param values
	 * @return
	 */
	public int findCountEntities(final String hql, final Object... values) {
		Object o = this.getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				Query query = session.createQuery(hql);
				int i = 0;
				for (Object object : values) {
					query.setParameter(i, object);
					i++;
				}
				return (query.iterate().next().toString());
			}
		});
		return Integer.parseInt(o.toString());
	}

	/**
	 * 
	 * @param <T>
	 * @param clazz
	 * @return
	 */
	public <T> List<T> getEntities(Class<T> clazz) {
		DetachedCriteria dc = DetachedCriteria.forClass(clazz);
		List list = this.getHibernateTemplate().findByCriteria(dc);
		return list;
	}

	/**
	 * 
	 * @param dc
	 * @return
	 */
	public Object findEntity(DetachedCriteria dc) {
		List list = this.getHibernateTemplate().findByCriteria(dc, 0, 1);
		if (list != null && list.size() > 0)
			return list.get(0);
		return null;
	}

	/**
	 * 
	 * @param dc
	 * @return
	 */
	public List findEntities(DetachedCriteria dc) {
		return this.getHibernateTemplate().findByCriteria(dc);
	}

	/**
	 * 
	 * @param dc
	 * @param offset
	 * @param count
	 * @return
	 */
	public List findEntities(DetachedCriteria dc, int offset, int count) {
		return this.getHibernateTemplate().findByCriteria(dc, offset, count);
	}

	/**
	 * 
	 * @param dc
	 * @return
	 */
	public int findCountEntities(final DetachedCriteria dc) {
		Object o = this.getHibernateTemplate().execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Criteria c = dc.getExecutableCriteria(session);
				c.setProjection(Projections.rowCount());
				int total = (Integer) c.uniqueResult();
				return total;
			}
		});
		return Integer.parseInt(o.toString());
	}

	/**
	 * 
	 * @param dc
	 * @param start
	 * @param count
	 * @return
	 */

	public List findEntitiesForPage(final DetachedCriteria dc, final int start,
			final int count) {
		return (List) this.getHibernateTemplate().execute(
				new HibernateCallback() {

					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Criteria c = dc.getExecutableCriteria(session);
						c.setProjection(Projections.rowCount());
						c.setProjection(null);
						c.setResultTransformer(Criteria.ROOT_ENTITY);
						c.setFirstResult(start);
						c.setMaxResults(count);
						List items = c.list();

						return items;
					}
				});
	}

	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
	}

	public SimpleJdbcTemplate getSimpleJdbcTemplate() {
		return this.jdbcTemplate;
	}

}
